home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 October: Mac OS SDK / Dev.CD Oct 00 SDK1.toast / Development Kits / Mac OS / Apple Guide / Engineering / AGSample / sample source / AGSampleCode.c < prev    next >
Encoding:
Text File  |  1996-04-15  |  26.8 KB  |  922 lines  |  [TEXT/MPS ]

  1. // AGSampleCode.c
  2. // Copyright 1996, Apple Computer, Inc.
  3. // Date:    23-Jan-96
  4. // Author:    guideWorks, LLC
  5. // Web:        http://www.guideworks.com
  6. // EMail:    powers@guideworks.com
  7. //
  8. // This file contains the Apple Guide integration code for the application.
  9. // See the AGSampleGuide for more information.
  10.  
  11. // AGSInstallCoachHandler
  12. // Install the coach mark handler.
  13.  
  14. // AGSRemoveCoachHandler
  15. // Remove the coach mark handler.
  16.  
  17. // AGSCoachReplyProc
  18. // Return the global rectangle of an object in the document window.
  19.  
  20. // AGSInstallContextHandler
  21. // Install the context check handler.
  22.  
  23. // AGSRemoveContextHandler
  24. // Remove the context check handler.
  25.  
  26. // AGSContextReplyProc
  27. // Reply to context checks.
  28.  
  29. // AGSInstallAEHandler
  30. // Install the Apple event handler.
  31.  
  32. // AGSRemoveAEHandler
  33. // Remove the Apple event handler.
  34.  
  35. // AGSHandleAEvents
  36. // Handles the custom events.
  37.  
  38. // AGSOpenGuide
  39. // Open the guide file in its default view.
  40.  
  41. // AGSOpenGuideWithSearch
  42. // Open the guide file with a search.
  43.  
  44. // AGSInstallASCoachHandlers
  45. // Install the handlers for AppleScript Coach
  46.  
  47. // AGSRemoveASCoachHandlers
  48. // Remove the handlers for AppleScript Coach
  49.  
  50. // AGSHandleGetData
  51. // Return a reply to the Get Data Apple Event for the requested data.
  52.  
  53. // AGSGetDataItemCoachRect
  54. // Get the property data for the item and return it in the result parameter.
  55.  
  56. // AGSCoachItemAccessor
  57. // Return the token for the coach item identifier.
  58.  
  59. // AGSCoachItemPropertyAccessor
  60. // Return a token representing the property for the coach item.
  61.  
  62. // ---------- Headers -----------------------------------------------------
  63.  
  64. #include "AGSampleCode.h"    // Headers for the Apple Guide sample code.
  65.  
  66. // ---------- Globals -----------------------------------------------------
  67.  
  68. AGCoachRefNum    gCoachRefNum;
  69. AGContextRefNum    gContextRefNum;
  70. AGRefNum        gGuideRefNum;
  71. FileRecHndl        ghFileRec;
  72. // ---------- General Functions -------------------------------------------
  73.  
  74. // ------------------------------------------------------------------------
  75. // AGSInstall
  76. // Install all handlers.
  77.  
  78. void
  79. AGSInstall()
  80. {
  81.     AGSInstallCoachHandler();
  82.     AGSInstallContextHandler();
  83.     AGSInstallASCoachHandlers();
  84.     AGSInstallAEHandler();
  85. }
  86.  
  87. // ------------------------------------------------------------------------
  88. // AGSRemove
  89. // Remove all handlers.
  90.  
  91. void
  92. AGSRemove()
  93. {
  94.     AGSRemoveCoachHandler();
  95.     AGSRemoveContextHandler();
  96.     AGSRemoveASCoachHandlers();
  97.     AGSRemoveAEHandler();
  98. }
  99.  
  100. // ---------- Object Coach Functions --------------------------------------
  101.  
  102. // ------------------------------------------------------------------------
  103. // AGSInstallCoachHandler
  104. // Install the coach mark handler.
  105.  
  106. OSErr
  107. AGSInstallCoachHandler()
  108. {
  109.     long myRefCon=0;
  110.  
  111.     return AGInstallCoachHandler(NewCoachReplyProc(AGSCoachReplyProc),
  112.                                                     myRefCon, &gCoachRefNum);
  113. }
  114.  
  115. // ------------------------------------------------------------------------
  116. // AGSRemoveCoachHandler
  117. // Remove the coach mark handler.
  118.  
  119. OSErr
  120. AGSRemoveCoachHandler()
  121. {
  122.     return AGRemoveCoachHandler(&gCoachRefNum);
  123. }
  124.  
  125. // ------------------------------------------------------------------------
  126. // AGSCoachReplyProc
  127. // Reply to object coach marks defined in AGSample Guide and sent by Apple Guide.
  128. // Return the global rectangle of the object whose name is given.
  129. // This is a reply function installed by AGSInstallCoachHandler.
  130. // Guide Script:
  131. // <Define Object Coach> "Coach open guide button", 'AGS2', REDCIRCLE, "1001"
  132. // <Define Object Coach> "Coach open guide with search button", 'AGS2', REDCIRCLE, "1002"
  133. // <Define Object Coach> "Coach checkbox", 'AGS2', REDCIRCLE, "2001"
  134. // For this sample application:
  135. //    target app is 'AGS2' (kAGSTargetAppSignature).
  136.  
  137. pascal OSErr
  138. AGSCoachReplyProc(Rect* pRect, Ptr name, long refCon)
  139. {
  140.     Boolean isFound=false;
  141.     WindowPtr pWin;
  142.         // The object name is passed as a string. Our "name" is the control identifier.
  143.         // <Define Object Coach> "Coach Open Guide button", 'AGS2', REDCIRCLE, "1001"
  144.         // <Define Object Coach> "Coach Checkbox", 'AGS2', REDCIRCLE, "2001"
  145.         // Apple guide passes the name as a null-terminated c-string.
  146.         // If we use 4-character names,
  147.         // then we can cast the name as an OSType to make comparisons easier.
  148.     OSType myNameAsOSType=*((OSType*)name);
  149.         // Or we can convert the c-string to a decimal number
  150.         // using an Apps-To-Go function.
  151.     long myNameAsDecNumber = c2dec(name, nil);
  152.         // Initialize the rect to an empty rect.
  153.     Rect globalRect;
  154.     SetRect(&globalRect, 0, 0, 0, 0);
  155.         // Check each document window.
  156.     for(pWin=nil; (pWin=GetNextDocumentWindow(pWin, 0))!=nil && !isFound;)
  157.         if(pWin)
  158.             if(((WindowPeek)pWin)->hilited)
  159.             {
  160.                     // We only coach if the window is front (active).
  161.                     // Get the window content rectangle.
  162.                 Rect winRect = GetWindowContentRect(pWin);
  163.                     // Get the control whose ID==myNameAsDecNumber.
  164.                 ControlHandle hCtrl;
  165.                 (void) CNum2Ctl(pWin, myNameAsDecNumber, &hCtrl);
  166.                 if(hCtrl)    
  167.                 {
  168.                         // Get the local rect of the control and convert to global.
  169.                     Rect ctrlRect = (**hCtrl).contrlRect;
  170.                     globalRect.top = ctrlRect.top + winRect.top;
  171.                     globalRect.left = ctrlRect.left + winRect.left;
  172.                     globalRect.bottom = winRect.top + ctrlRect.bottom;
  173.                     globalRect.right = winRect.left + ctrlRect.right;
  174.                     isFound = true;
  175.                 }
  176.             }
  177.         // Return the rectangle for the object.
  178.     *pRect = globalRect;
  179.         // If you want the coach mark drawn, return noErr.
  180.         // If you don't want the coach mark drawn, return kAGErrItemNotFound.
  181.     return (isFound)?noErr:kAGErrItemNotFound;
  182. }
  183.  
  184. // ---------- Context Functions -------------------------------------------
  185.  
  186. // ------------------------------------------------------------------------
  187. // AGSInstallContextHandler
  188. // Install the context check handler.
  189.  
  190. OSErr
  191. AGSInstallContextHandler()
  192. {
  193.     AEEventID    contextEventID=kAGSContextCodeResSpec;
  194.     long        myRefCon=nil;
  195.     
  196.     return AGInstallContextHandler(NewContextReplyProc(AGSContextReplyProc),
  197.                                     contextEventID, myRefCon, &gContextRefNum);
  198. }
  199.  
  200. // ------------------------------------------------------------------------
  201. // AGSRemoveContextHandler
  202. // Remove the context check handler.
  203.  
  204. OSErr
  205. AGSRemoveContextHandler()
  206. {
  207.     return AGRemoveContextHandler(&gContextRefNum);
  208. }
  209.  
  210. // ------------------------------------------------------------------------
  211. // AGSContextReplyProc
  212. // Reply to context checks defined in AGSample Guide and sent by Apple Guide.
  213. // This is a reply function installed by AGSInstallContextHandler.
  214. // Guide Script:
  215. // <Define Context Check> "IsAnyDocumentOpen", 'agsd', 'AGS2', LONG:1, LONG:0
  216. // <Define Context Check> "IsThisControlFront", 'agsd', 'AGS2', LONG:2, LONG
  217. // <Define Context Check> "IsThisControlTrue", 'agsd', 'AGS2', LONG:3, LONG
  218. // For this sample application:
  219. //    target app is 'AGS2' (kAGSTargetAppSignature).
  220. //    code resource spec is 'agsd' (kAGSContextCodeResSpec).
  221. //
  222. // We install separate handlers, each with its own event ID.
  223. // However, for this sample, we use a single handler
  224. // and pass a selector in the input data.
  225.  
  226. pascal OSErr
  227. AGSContextReplyProc(Ptr pInputData, Size inputDataSize,
  228.                                 Ptr *ppOutputData, Size *pOutputDataSize, 
  229.                                 AGAppInfoHdl hAppInfo)
  230. {
  231.     Ptr                pResult;
  232.     WindowPtr        pWin;
  233.     ControlHandle    hCtrl;
  234.     OSErr            err=noErr;
  235.     Boolean            result=false;
  236.     Boolean            isFound=false;
  237.     InputDataPtr    pMyInputData=(InputDataPtr)pInputData;
  238.     
  239.         // See what is to be checked.
  240.     if(inputDataSize==sizeof(InputDataType))
  241.     {
  242.         switch (pMyInputData->checkSelector)
  243.         {
  244.             case kAGSCheckSelectorDocumentAny:
  245.                     // Is any document open?
  246.                 result = (GetWindowCount(false, false, false)>0);
  247.                 break;
  248.             case kAGSCheckSelectorControlFront:
  249.                     // Is this control front?
  250.                     // Check each document window.
  251.                 for(pWin=nil; (pWin=GetNextDocumentWindow(pWin, 0))!=nil && !isFound;)
  252.                     if(pWin)
  253.                     {
  254.                             // See if the control is in this document window.
  255.                         (void) CNum2Ctl(pWin, pMyInputData->itemIdentifier, &hCtrl);
  256.                         if(hCtrl)    
  257.                         {
  258.                                 // Control is in this window, is window front?
  259.                             result = ((WindowPeek)pWin)->hilited;
  260.                             isFound = true;
  261.                         }
  262.                     }
  263.                 break;
  264.             case kAGSCheckSelectorControlTrue:
  265.                     // Is this control true?
  266.                     // Check each document window.
  267.                 for(pWin=nil; (pWin=GetNextDocumentWindow(pWin, 0))!=nil && !isFound;)
  268.                     if(pWin)
  269.                     {
  270.                             // See if the control is in this document window.
  271.                         (void) CNum2Ctl(pWin, pMyInputData->itemIdentifier, &hCtrl);
  272.                         if(hCtrl)    
  273.                         {
  274.                                 // Get value of the control.
  275.                             result = ((**hCtrl).contrlValue==1);
  276.                             isFound = true;
  277.                         }
  278.                     }
  279.                 break;
  280.             default:
  281.                 break;
  282.         }
  283.     }
  284.         // Convert result to a form that Apple Guide understands.
  285.     pResult = NewPtr(sizeof(Boolean));
  286.     if (pResult)
  287.     {
  288.         BlockMoveData(&result, pResult, sizeof(Boolean));
  289.         *ppOutputData = pResult;
  290.         *pOutputDataSize = sizeof(Boolean);
  291.     }
  292.     else
  293.         err = MemError();
  294.     
  295.     return err;
  296. }
  297.  
  298. // ---------- Apple event Functions ---------------------------------------
  299.  
  300. // ------------------------------------------------------------------------
  301. // AGSInstallAEHandler
  302. // Install the Apple event handler.
  303.  
  304. OSErr
  305. AGSInstallAEHandler()
  306. {
  307.     long myRefCon=0;
  308.  
  309.     return AEInstallEventHandler(kAGSAEventClass,
  310.                                 typeWildCard,
  311.                                 NewAEEventHandlerProc(AGSHandleAEvents),
  312.                                 myRefCon, false);
  313. }
  314.  
  315. // ------------------------------------------------------------------------
  316. // AGSRemoveAEHandler
  317. // Remove the Apple event handler.
  318.  
  319. OSErr
  320. AGSRemoveAEHandler()
  321. {
  322.     return AERemoveEventHandler(kAGSAEventClass, typeWildCard, false, false);
  323. }
  324.  
  325. // ------------------------------------------------------------------------
  326. // AGSHandleAEvents
  327. // Handles the custom events defined in AGSample Guide and sent by Apple Guide.
  328. // This is a function installed by AEInstallEventHandler.
  329. // Guide Script:
  330. // <Define Event> "OpenNewDocument", 'AGS2', 'agse', 'agsw'
  331. // <Define Event> "CloseDocument", 'AGS2', 'agse', 'agsx'
  332. // For this sample application:
  333. //    target app is 'AGS2' (kAGSTargetAppSignature).
  334. //    event class is 'agse' (kAGSAEventClass).
  335. //    event id is 'agsw' (kAGSAEventOpenNewDocument) and 'agsx' (kAGSAEventCloseDocument).
  336.  
  337. pascal OSErr
  338. AGSHandleAEvents(AppleEvent* pAppleEvent,
  339.                                 AppleEvent* /*theReply*/, long refCon)
  340. {
  341.     OSType        eventId;
  342.     Size        actualSize;
  343.     DescType    returnedType;
  344.     WindowPtr    pWin;
  345.     Boolean        isFound=false;
  346.     OSErr        err=noErr;
  347.             // Get event id.
  348.     err = AEGetAttributePtr(pAppleEvent, keyEventIDAttr,
  349.                                 typeType, &returnedType,
  350.                                 (Ptr) &eventId, sizeof(eventId),
  351.                                 &actualSize);
  352.             // Do event.
  353.     switch (eventId)
  354.     {
  355.         case kAGSAEventOpenNewDocument:
  356.                 // Open new document
  357.             err = NewDocument(&ghFileRec, kAGSDocSFType, true);
  358.             if(err==noErr)
  359.                 err = DoNewWindow(ghFileRec, &pWin, nil, (WindowPtr)-1);
  360.             break;
  361.         case kAGSAEventCloseDocument:
  362.                 // Close front document
  363.             for(pWin=nil; (pWin=GetNextDocumentWindow(pWin, 0))!=nil && !isFound;)
  364.                 if(pWin)
  365.                     if(((WindowPeek)pWin)->hilited)
  366.                     {
  367.                         (void) DisposeOneWindow(pWin, false);
  368.                         isFound = true;
  369.                     }
  370.             break;
  371.         default:
  372.             err = errAEEventNotHandled;
  373.             break;
  374.     }
  375.     return err;
  376. }
  377.  
  378. // ---------- Open Functions ----------------------------------------------
  379.  
  380. // ------------------------------------------------------------------------
  381. // OpenGuide
  382. // Open the default guide file.
  383.  
  384. OSErr
  385. AGSOpenGuide()
  386. {
  387.     FSSpec    *pFileSpec=nil;        // Want first guide file of type Help.
  388.     UInt32    flags=0;
  389.     Handle    hMixinControl=nil;
  390.     return AGOpen(pFileSpec, flags, hMixinControl, &gGuideRefNum);
  391. }
  392.  
  393. // ------------------------------------------------------------------------
  394. // AGSOpenGuideWithSearch
  395. // Open the guide file with search.
  396. // Use the search phrase whose index is given.
  397. // We could do a simple open of the guide file with a search string,
  398. // but we elect to keep the search strings as a STR# resource in
  399. // the guide file. As a result, the application doesn't need to
  400. // know or maintain the strings, but can refer to them by an index.
  401. // The strings are maintained by the guide author and stored
  402. // in the guide using a <resource> command.
  403. // This also gives us a chance to show a use for AGFileLib.
  404.  
  405. OSErr
  406. AGSOpenGuideWithSearch(short searchPhraseIndex)
  407. {
  408.     FSSpec    *pFileSpec=nil;
  409.     UInt32    flags=0;
  410.     Handle    hMixinControl=nil;
  411.     Boolean    wantMixin=false;
  412.     Str255    pSearchPhrase;
  413.     FSSpec    fileSpec;
  414.     short    vRefNum;
  415.     long    dirID;
  416.     short    guideRefNum;
  417.     OSErr    result;
  418.         // Get the file spec for this application.
  419.     result = AGSGetAppFSSpec(&fileSpec);
  420.     if(result==noErr)
  421.     {
  422.         vRefNum = fileSpec.vRefNum;
  423.         dirID = fileSpec.parID;
  424.             // Use AGFileLib to get the file spec
  425.             // for the first guide file of guide type HELP.
  426.         result = AGFileGetIndDB(vRefNum, dirID, kAGFileDBTypeHelp,
  427.                                                 wantMixin, 1, &fileSpec);
  428.         if(result==noErr)
  429.         {
  430.                 // Open guide file resource fork.
  431.             guideRefNum = FSpOpenResFile(&fileSpec, fsRdPerm);
  432.             if(guideRefNum!=-1)
  433.             {
  434.                     // Get search phrase from guide file resource fork.
  435.                 GetIndString(pSearchPhrase, kAGSSearchPhraseID, searchPhraseIndex);
  436.                     // Done with guide file.
  437.                 (void) FSClose(guideRefNum);
  438.                     // Open guide file with search phrase.
  439.                 if(pSearchPhrase[0]>0)
  440.                     result = AGOpenWithSearch(&fileSpec, flags, hMixinControl,
  441.                                                 pSearchPhrase, &gGuideRefNum);
  442.             }
  443.         }
  444.     }
  445.     return result;
  446. }
  447.  
  448. // ------------------------------------------------------------------------
  449. // AGSGetAppFSSpec
  450. // Returns the FSSpec of this application.
  451. // We use this to establish the path for the associated guide file.
  452. //
  453. OSErr
  454. AGSGetAppFSSpec(FSSpec* pFileSpec)
  455. {
  456.     ProcessSerialNumber    currentProcess;
  457.     ProcessInfoRec        infoRec;
  458.     OSErr                result;
  459.     
  460.     currentProcess.highLongOfPSN = 0;
  461.     currentProcess.lowLongOfPSN = kCurrentProcess;
  462.     infoRec.processInfoLength = sizeof(infoRec);
  463.     infoRec.processName = nil;
  464.     infoRec.processAppSpec = pFileSpec;
  465.     result = GetCurrentProcess(¤tProcess);
  466.     if(result==noErr)
  467.         result = GetProcessInformation(¤tProcess, &infoRec);
  468.     return result;
  469. }
  470.  
  471. // ---------- AppleScript Coach Functions ---------------------------------
  472.  
  473. // ------------------------------------------------------------------------
  474. // AGSInstallASCoachHandlers
  475. // Install the handlers for AppleScript Coach
  476.  
  477. OSErr
  478. AGSInstallASCoachHandlers()
  479. {
  480.     OSErr result;
  481.             // Apple event handler
  482.     result = AEInstallEventHandler(kAECoreSuite,
  483.                             kAEGetData,
  484.                             NewAEEventHandlerProc(AGSHandleGetData),
  485.                             kAEGetData,
  486.                             false);
  487.     if(result!=noErr)
  488.         return result;
  489.             // Object accessors
  490.     result = AEObjectInit();
  491.     if(result!=noErr)
  492.         return result;
  493.     result = AEInstallObjectAccessor(cAGSASCoachItem, typeNull,
  494.                                 NewOSLAccessorProc(AGSCoachItemAccessor),
  495.                                 nil,
  496.                                 false);
  497.     if(result!=noErr)
  498.         return result;
  499.     result = AEInstallObjectAccessor(cProperty, cAGSASCoachItem,
  500.                                 NewOSLAccessorProc(AGSCoachItemPropertyAccessor),
  501.                                 nil,
  502.                                 false);
  503.     return result;
  504. }
  505.  
  506. // ------------------------------------------------------------------------
  507. // AGSRemoveASCoachHandlers
  508. // Remove the handlers for AppleScript Coach
  509.  
  510. OSErr
  511. AGSRemoveASCoachHandlers()
  512. {
  513.     OSErr result;
  514.             // Apple event handler
  515.     result = AERemoveEventHandler(kAECoreSuite, kAEGetData, 
  516.                                     nil, false);
  517.     if(result!=noErr)
  518.         return result;
  519.             // Object accessors
  520.     result = AERemoveObjectAccessor(cAGSASCoachItem, typeNull, 
  521.                                     nil, false);
  522.     if(result!=noErr)
  523.         return result;
  524.     result = AERemoveObjectAccessor(cProperty, cAGSASCoachItem, 
  525.                                     nil, false);
  526.     return result;
  527. }
  528.  
  529. // ------------------------------------------------------------------------
  530. // AGSHandleGetData
  531. // Return a reply to the Get Data Apple Event for the requested data.
  532. // The error, if any, is returned as a result.
  533.  
  534. pascal OSErr
  535. AGSHandleGetData(AppleEvent* theAppleEvent,
  536.                             AppleEvent* reply,
  537.                              long refCon)
  538. {
  539.     OSErr        result=noErr;
  540.     DescType    reqType;
  541.     Size        theSize;
  542.     AEDesc        target;
  543.     target.descriptorType = typeNull;
  544.     target.dataHandle = nil;
  545.         //    First, get the direct object.
  546.     result = AEGetParamDesc(theAppleEvent, keyDirectObject,
  547.                             typeObjectSpecifier, &target);
  548.     if(result==noErr)
  549.     {
  550.             //    Next, get the requested return type, if it exists.
  551.         result = AEGetParamPtr(theAppleEvent, keyAERequestedType, typeType, &reqType,
  552.                                     (Ptr)&reqType, sizeof(DescType), &theSize);
  553.         if(result == errAEDescNotFound)
  554.         {
  555.                 // not an error if return type is not found
  556.             result = noErr;
  557.             reqType = typeWildCard;
  558.         }
  559.         if(result==noErr)
  560.         {
  561.                     // check for missing params
  562.             result = AGSIsMissingParams(theAppleEvent);
  563.             if(result==noErr)
  564.             {
  565.                 AEDesc token;        // direct object and resolved token.
  566.                 AEDesc objectData;    // object data.
  567.                 token.descriptorType = typeNull;
  568.                 token.dataHandle = nil;
  569.                 objectData.descriptorType = typeNull;
  570.                 objectData.dataHandle = nil;
  571.                         // Resolve the object specifier
  572.                         // and get the token containing the property and container.
  573.                 result = AEResolve(&target, kAEIDoMinimum, &token);
  574.                 if(result==noErr)
  575.                 {
  576.                         // The container is nil for the application.
  577.                     if(token.dataHandle!=nil)
  578.                         result = AGSGetDataItemCoachRect(&token, &objectData);
  579.                     else
  580.                         result = errAEEventNotHandled;
  581.                     AEDisposeDesc(&token);
  582.                 }
  583.                 if(result==noErr && reply->dataHandle!=nil)
  584.                 {
  585.                         //    Add data to the reply Apple event record.
  586.                     if (reqType != typeWildCard
  587.                         && reqType != typeBest
  588.                         && reqType != objectData.descriptorType)
  589.                     {
  590.                             // Do not use the same descriptor
  591.                             // as source and dest in AECoerceDesc().
  592.                             // This routine creates a copy of the source,
  593.                             // and then it is impossible to dispose of the memory
  594.                             // originally contained in the source's dataHandle.
  595.                         AEDesc tempDesc;    // coerced data
  596.                         result = AECoerceDesc(&objectData, reqType, &tempDesc);
  597.                         AEDisposeDesc(&objectData);
  598.                         objectData.descriptorType = tempDesc.descriptorType;
  599.                         objectData.dataHandle = tempDesc.dataHandle;
  600.                     }
  601.                     if(result==noErr)
  602.                         result = AEPutParamDesc(reply, keyAEResult, &objectData);
  603.                 }
  604.                 AEDisposeDesc(&objectData);
  605.             }
  606.         }
  607.     }
  608.     AEDisposeDesc(&target);
  609.  
  610.     return result;
  611. }
  612.  
  613. // ------------------------------------------------------------------------
  614. // AGSGetDataItemCoachRect
  615. // Get the property data for the item and return it in the result parameter.
  616. // The result token contains the property type in the descriptorType field, and
  617. // a nil value in the dataHandle field to represent the null application.
  618.  
  619. OSErr
  620. AGSGetDataItemCoachRect(AEDesc* token, AEDesc* pResult)
  621. {
  622.     DescType    theProperty=token->descriptorType;
  623.     long        coachItemIdentifier=(long) **(DescType**)token->dataHandle;
  624.     Boolean        isFound=false;
  625.     WindowPtr    pWin;
  626.     Rect        globalRect;
  627.     OSErr        result=noErr;
  628.     
  629.     switch (theProperty)
  630.     {
  631.         case pAGSASCoachRect:
  632.                 // Initialize the rect to an empty rect.
  633.             SetRect(&globalRect, 0, 0, 0, 0);
  634.                 // Check each document window.
  635.             for(pWin=nil; (pWin=GetNextDocumentWindow(pWin, 0))!=nil && !isFound;)
  636.                 if(pWin)
  637.                     if(((WindowPeek)pWin)->hilited)
  638.                     {
  639.                             // We only coach if the window is front (active).
  640.                             // Get the window content rectangle.
  641.                         Rect winRect = GetWindowContentRect(pWin);
  642.                             // Get the control whose ID==myNameAsDecNumber.
  643.                         ControlHandle hCtrl;
  644.                         (void) CNum2Ctl(pWin, coachItemIdentifier, &hCtrl);
  645.                         if(hCtrl)    
  646.                         {
  647.                                 // Get the local rect of the control and convert to global.
  648.                             Rect ctrlRect = (**hCtrl).contrlRect;
  649.                             globalRect.top = ctrlRect.top + winRect.top;
  650.                             globalRect.left = ctrlRect.left + winRect.left;
  651.                             globalRect.bottom = winRect.top + ctrlRect.bottom;
  652.                             globalRect.right = winRect.left + ctrlRect.right;
  653.                             isFound = true;
  654.                         }
  655.                     }
  656.                 // If you want the coach mark drawn, return noErr.
  657.                 // If you don't want the coach mark drawn, return kAGErrItemNotFound.
  658.             if(isFound)
  659.             {
  660.                     // Create an AEDesc returning the global rectangle for the object.
  661.                 result = AECreateDesc(typeQDRectangle, &globalRect,
  662.                                         sizeof(globalRect), pResult);
  663.             }
  664.             else
  665.                 result = kAGErrItemNotFound;
  666.             break;
  667.  
  668.         default:                // We don't handle the requested property.
  669.             result = errAEEventNotHandled;
  670.     }
  671.     return result;
  672. }
  673.  
  674. // ------------------------------------------------------------------------
  675. // AGSCoachItemAccessor
  676. // Return the token for the coach item identifier.
  677. // In our sample, we pass a number identifying the item to coach.
  678. // If you want to pass a string, use AGSDescToPString
  679. // instead of AGSDescToLong.
  680.  
  681. pascal OSErr
  682. AGSCoachItemAccessor(    DescType    desiredClass,
  683.                           AEDesc*        containerToken,
  684.                         DescType    containerClass, 
  685.                         DescType    keyForm,
  686.                         AEDesc*        keyData,
  687.                         AEDesc*        resultToken,
  688.                         long         refCon)
  689. {
  690.     OSErr    result=noErr;
  691.     long    coachItemIdentifier;
  692.     switch (keyForm)
  693.     {
  694.         case formName:
  695.                 // coachItem name - get the name from the keyData.
  696.                 // We could coerce the name to a PString,
  697.                 // but since we're using numeric identifiers,
  698.                 // we coerce the name to a long.
  699.             result = AGSDescToLong(keyData, &coachItemIdentifier);
  700.             break;
  701.  
  702.         default:
  703.             result = errAEEventNotHandled;
  704.     }
  705.     if(result==noErr)
  706.         result = AECreateDesc(cAGSASCoachItem, (Ptr)&coachItemIdentifier,
  707.                                 sizeof(coachItemIdentifier), resultToken);
  708.     return result;
  709. }
  710.  
  711. // ------------------------------------------------------------------------
  712. // AGSCoachItemPropertyAccessor
  713. // Return a token representing the property for the coach item.
  714. // The storage object is referenced by the containerToken dataHandle.
  715. // The token is returned with the property and the storage object.
  716. // Note the casting required to get the storage object.
  717.  
  718. pascal OSErr
  719. AGSCoachItemPropertyAccessor(    DescType    desiredClass,
  720.                                   AEDesc*        containerToken,
  721.                                 DescType    containerClass, 
  722.                                 DescType    keyForm,
  723.                                 AEDesc*        keyData,
  724.                                 AEDesc*        resultToken,
  725.                                 long         refCon)
  726. {
  727.     OSErr result=noErr;
  728.         // Let's make sure we're accessing a valid descriptor type.
  729.         // If formPropertyID, keyData descriptorType is typeType.
  730.         // If formUserPropertyID, keyData descriptorType is defined in aete.
  731.     if (desiredClass != cProperty
  732.         || !(keyForm == formPropertyID || keyForm == formUserPropertyID))
  733.         result = errAEWrongDataType;
  734.     else if(!(containerToken->descriptorType==cAGSASCoachItem))
  735.         result = errAETypeError;
  736.     else
  737.     {
  738.         long coachItemIdentifier = (long) **(DescType**)containerToken->dataHandle;
  739.                 // Get the property type.        
  740.         DescType requestedProperty = **(DescType**)keyData->dataHandle;
  741.         result = AECreateDesc(requestedProperty, (Ptr)&coachItemIdentifier,
  742.                                     sizeof(coachItemIdentifier), resultToken);
  743.     }
  744.     return result;
  745. }
  746.  
  747. // ------------------------------------------------------------------------
  748. // AGSIsMissingParams
  749. // Check to see if there exists any additional parameters in the Apple Event.
  750. // If so, return an error to the calling routine.
  751.  
  752. OSErr
  753. AGSIsMissingParams(AppleEvent*  theAppleEvent)
  754. {
  755.     DescType    theType;
  756.     Size        actualSize;
  757.     OSErr        err;
  758.     
  759.     err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
  760.                                 &theType, nil, 0, &actualSize);
  761.     if (err == errAEDescNotFound)
  762.         err = noErr;
  763.     else
  764.         err = errAEEventNotHandled;
  765.     return err;
  766. }
  767.  
  768. // ------------------------------------------------------------------------
  769. // AGSDescToLong
  770. // Converts a descriptor to a long.
  771.  
  772. OSErr
  773. AGSDescToLong(const  AEDesc* desc, long* pLongValue)
  774. {
  775.     AEDesc    tempDesc;
  776.     OSErr    result=noErr;
  777.  
  778.     tempDesc.descriptorType = typeNull;
  779.     tempDesc.dataHandle = nil;
  780.         // If we have a typeLongInteger, use as-is. Otherwise coerce.
  781.     if (desc->descriptorType == typeLongInteger)
  782.         tempDesc.dataHandle = desc->dataHandle;
  783.     else
  784.         result = AECoerceDesc(desc, typeLongInteger, &tempDesc);
  785.     if(result==noErr)
  786.     {
  787.         Handle dataHandle = tempDesc.dataHandle;
  788.             // Copy long from dereferenced data handle
  789.             // to dereferenced long pointer.
  790.         *pLongValue = **(long**)dataHandle;
  791.     }
  792.     AEDisposeDesc(&tempDesc);
  793.  
  794.     return result;
  795. }
  796.  
  797. // ------------------------------------------------------------------------
  798. // AGSDescToPString
  799. // Converts a descriptor to a pascal string.
  800. // This function is not used in the sample,
  801. // but you can use it if you pass a string instead of a number
  802. // to identify the item to coach.
  803.  
  804. OSErr
  805. AGSDescToPString(const AEDesc* desc, StringPtr pStr, short maxLength)
  806. {
  807.     AEDesc    tempDesc;
  808.     Handle    dataHandle;
  809.     long    charCount;
  810.     OSErr    result=noErr;
  811.         // If we have typeChar, use as-is. Otherwise coerce to typeChar.
  812.     tempDesc.descriptorType = typeNull;
  813.     tempDesc.dataHandle = nil;
  814.     if (desc->descriptorType == typeChar)
  815.         dataHandle = desc->dataHandle;
  816.     else
  817.     {
  818.         result = AECoerceDesc(desc, typeChar, &tempDesc);
  819.         if(result==noErr)
  820.             dataHandle = tempDesc.dataHandle;
  821.     }
  822.     if(result==noErr)
  823.     {
  824.         charCount = GetHandleSize(dataHandle);
  825.         if (charCount > maxLength)
  826.         {
  827.             result = errAECoercionFail;
  828.         }
  829.         if(result==noErr)
  830.         {
  831.             pStr[0] = charCount;
  832.             HLock(dataHandle);
  833.             BlockMoveData(*dataHandle, &pStr[1], charCount);
  834.             HUnlock(dataHandle);        // This may be from desc, so must unlock.
  835.         }
  836.     }
  837.     AEDisposeDesc(&tempDesc);
  838.  
  839.     return result;
  840. }
  841.  
  842. // ---------- Apps-To-Go Functions ---------------------------------
  843.  
  844. // These functions were taken from Apps-To-Go
  845. // and lightly customized for the Apple Guide sample application.
  846. // They are not required for Apple Guide integration.
  847.  
  848. // ------------------------------------------------------------------------
  849. // ContentClick
  850. // From Window.c
  851. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  852. /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
  853. ** a window.  Other applications might want to call FindControl, TEClick, etc., to
  854. ** further process the click. */
  855.  
  856. void
  857. ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
  858. {
  859.     ControlHandle    ctl;
  860.     short            action, cnum;
  861.  
  862. #pragma unused firstClick
  863.  
  864.     cnum = IsCtlEvent(window, event, &ctl, &action);
  865.         /* That was easy.  Scrolling was just handled.  Other stuff would be handled
  866.         ** by IsCtlEvent, if we had other stuff to do.  We don't have any other
  867.         ** controls in the content besides the document scrollbars. */
  868.         // The two case statements were added for AGSample.
  869.     switch (cnum)
  870.     {
  871.         case kAGSOpenGuideId:
  872.             (void) AGSOpenGuide();
  873.             break;
  874.         case kAGSOpenGuideWithSearchId:
  875.             (void) AGSOpenGuideWithSearch(1);
  876.             break;
  877.         default:
  878.             break;
  879.     }
  880.  
  881.     return;
  882. }
  883.  
  884. #ifdef applec
  885. #pragma segment Main
  886. #endif
  887.  
  888. // ------------------------------------------------------------------------
  889. // main
  890. // From Start.c
  891. // Removed a few unnecessary functions.
  892.  
  893. void
  894. main(void)
  895. {
  896.  
  897.     #ifdef applec
  898.         UnloadSeg((Ptr)_DataInit);        /* Note that _DataInit can't be in Main! */
  899.     #endif
  900.  
  901.     SetApplLimit(GetApplLimit() - 16384);
  902.         /* This decreases the application heap by 16k, which in turn
  903.         ** increases the stack by 16k. */
  904.     MaxApplZone();                    /* Expand the heap so code segments load at the top. */
  905.     InitATGLIB();
  906.     Initialize(32, kMinHeap, kMinSpace, nil, nil);    /* Initialize the program. */
  907.     DoSetResCursor(watchCursor);                    /* Rest of startup may take a while. */
  908.     InitRequiredAppleEvents();
  909.     DoOpenApplication();                    /* Now must be in front of GetWindowFormats call. */
  910.     GetWindowFormats();                        /* Get the window definition resource information. */
  911.     OpenRuntimeOnlyAutoNewWindows();
  912.     DoAdjustMenus();
  913.     UnloadSeg((Ptr)Initialize);        /* Initialize can't be in Main! */
  914.  
  915.     AGSInstall();                    // Added for AGSample
  916.     EventLoop();                    /* Call the main event loop. */
  917.     AGSRemove();                    // Added for AGSample
  918.  
  919.     ExitToShell();                    /* Quit the application. */
  920. }
  921.  
  922.